package com.hp.bon.sgw.wh.channel.handler;

import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hp.bon.sgw.Constants;
import com.hp.bon.sgw.Constants.MessageType;
import com.hp.bon.sgw.bean.XmlMessage;
import com.hp.bon.sgw.core.BuzProcessorManager;
import com.hp.bon.sgw.core.CallParam;
import com.hp.bon.sgw.core.channel.SoapChannel;
import com.hp.bon.sgw.core.channel.handler.IAsynCallHandler;
import com.hp.bon.sgw.domain.MessageDetail;
import com.hp.bon.sgw.threads.MessageDetailCacheManager;
import com.hp.bon.sgw.threads.TaskManager;
import com.hp.bon.sgw.wh.bean.BillInfomation;
import com.hp.bon.sgw.wh.bean.BlackCardMsgIn;
import com.hp.bon.sgw.wh.bean.BlackCardMsgOUt;
import com.hp.bon.sgw.wh.bean.DataInfomation;
import com.hp.bon.sgw.wh.service.BlackCardConfigService;
import com.hp.bon.sgw.wh.utils.XmlUtils;
import com.hp.ocs.diameter.message.Message;

public class BlackCardHandler implements IAsynCallHandler {

	private static final Logger logger = LoggerFactory.getLogger(BlackCardHandler.class);
	private PrintStream printStream;
	private BlackCardMsgIn blackCardMsgIn;
	private HttpClient httpClient;
	private XmlMessage xmlMessage;
	private String accNbr;
	private String billingMode;
	private MultiThreadedHttpConnectionManager connectionManager;
	private BlackCardConfigService blackCardConfigService;
	public BlackCardHandler(PrintStream printStream, BlackCardMsgIn blackCardMsgIn,
			BlackCardConfigService blackCardConfigService,String accNbr,String billingMode) {
		this.accNbr = accNbr;
		this.billingMode = billingMode;
		this.printStream = printStream;
		this.blackCardMsgIn = blackCardMsgIn;
		this.blackCardConfigService = blackCardConfigService;
		connectionManager = new MultiThreadedHttpConnectionManager();
		HttpConnectionManagerParams connectionManagerParams = new HttpConnectionManagerParams();
		connectionManagerParams.setDefaultMaxConnectionsPerHost(50);
		connectionManagerParams.setMaxTotalConnections(200);
		connectionManagerParams.setTcpNoDelay(true);
		connectionManagerParams.setConnectionTimeout(10000);
		connectionManagerParams.setSoTimeout(45000);
		connectionManager.setParams(connectionManagerParams);
		httpClient = new HttpClient(connectionManager);

	}

	public String getBillingMode() {
		return billingMode;
	}

	public void setBillingMode(String billingMode) {
		this.billingMode = billingMode;
	}

	public String getAccNbr() {
		return accNbr;
	}

	public void setAccNbr(String accNbr) {
		this.accNbr = accNbr;
	}

	@Override
	public void onCallResult(CallParam callParam) {
		if (logger.isInfoEnabled()) 
		{
			logger.info(" onCallResult  ");
		}
		
		Object response = null;
		if (callParam.getResponse() != null) {
			response = callParam.getResponse();
		} else if (callParam.getRecvResponse() != null) {
			response = callParam.getRecvResponse();
		}

		//将内部网元返回的DCC协议的应答消息(CCA)为SOAP消息
		if (response == null) {
			logger.warn(" onCallResult  response == null ");
			setXmlMessage(SoapChannel.createERRAnwser(
					callParam.getSessionId(),
					callParam.getRetCode() == 3002 ? 11202 : callParam
							.getRetCode(), callParam.getResultMsg()));
		} else {
			if (response instanceof Message) {// CCA -> XML
				logger.info("MessageMessage ");
				
				setXmlMessage(BuzProcessorManager.getInstance().convertMessageToAck(
						callParam));
			} else if (response instanceof XmlMessage) {
				
				logger.info("XmlMessageXmlMessage ");
				setXmlMessage((XmlMessage) response);
			} else {
				logger.warn("response type:"
						+ callParam.getResponse().getClass().getName());
			}
		}
		try {
			
			logger.info("blackHandler++"+callParam.getServiceResultCode());
			//将响应消息输出到网厅
			String respXML = makeResponsMsg();
//			byte[] resp = respXML.getBytes("UTF-8");
			byte[] resp = respXML.getBytes();
			xmlMessage.setLength(resp.length);
			xmlMessage.setMsgTime(System.currentTimeMillis());
			printStream.write(resp);
			printStream.close();
			
			callParam.setResponse(xmlMessage);
			if (callParam.getRetCode() == Constants.ResultCode.SUCCESS) {
				// 成功的消息，请求应答入库
				MessageDetail detail = new MessageDetail();
				detail.setBusinessCallId(callParam.getBussinessCallId());
				detail.setSessionId(callParam.getSessionId());
				detail.setServiceContextId(callParam.getServiceContextId());
				detail.setMessageType(MessageType.WSA);
				detail.setDetails(respXML.toString());
				detail.setMsgTime(new Date(getXmlMessage().getMsgTime()));
				detail.setOpType("send");
				detail.setHostId(callParam.getUserName());
				MessageDetailCacheManager.getInstance().add(detail);
			}

			TaskManager.taskProcess(callParam);
			if (logger.isInfoEnabled()) {
				logger.info("http response (wt) " + respXML);
			}

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 生成外网相应消息 
	 * @param xmlMessage SAOP消息
	 * @return
	 */
	protected String makeResponsMsg() {
		StringBuilder respXML = new StringBuilder();
		//SOAP消息有错误，生成网厅错误应答
		if (Integer.valueOf(xmlMessage.getRC()).intValue() != 0) {
			if (logger.isInfoEnabled()) 
			{
				logger.info(" xmlMessage.getRC() SOAP消息有错误，生成网厅错误应答 ");
			}
			respXML.append(makeErrFormCCA());
		} else {
			String orinData = xmlMessage.getDATA();
			if (orinData != null) {
				Document doc = null;
				String result = "0";
				//云平台黑卡查询接口URL-暂时未定
				String url = blackCardConfigService.getValue("blackcardquery.url", "");
				PostMethod method = new PostMethod(url);
				
				try {
					if (logger.isInfoEnabled()) 
					{
						logger.info(" 获取CCA转换后的xml格式的响应数据，orinData :"+orinData );
					}
					doc = DocumentHelper.parseText(orinData);
					Element root = doc.getRootElement();
					result = XmlUtils.getNodevalue(root,"//Service_Information/Result");
					blackCardMsgIn.setServId(XmlUtils.getNodevalue(root,"//Service_Information/Data_Information/serv_id"));
					
					
					if(!billingMode.isEmpty()&&!billingMode.equals("")){
						blackCardMsgIn.setBillingMode(billingMode);	
					}else{
						//改动后： 0：后付费C网1：预付费C网；2：固话改点1,在调用云平台的接口之前，给BillingMod赋值规则修改；
						if(accNbr.startsWith("1")&&accNbr.length()==11){
							blackCardMsgIn.setBillingMode(XmlUtils.getNodevalue(root,"//Service_Information/Data_Information/PaymentFlag"));
						}else{
							blackCardMsgIn.setBillingMode("2");	
						}
					}
					
					
					//本地网区号 网厅AccNbr:027,CCA HomeAreaCode:1001(发云平台时需要HomeAreaCode)
					blackCardMsgIn.setAreaCode(XmlUtils.getNodevalue(root,"//Service_Information/Data_Information/HomeAreaCode"));
					
					if (logger.isInfoEnabled()) 
					{
						logger.info("result:"+result);
						logger.info("HomeAreaCode:"+XmlUtils.getNodevalue(root,"//Service_Information/Data_Information/HomeAreaCode"));
						logger.info("PaymentFlag:"+XmlUtils.getNodevalue(root,"//Service_Information/Data_Information/PaymentFlag"));
						logger.info("serv_id:"+XmlUtils.getNodevalue(root,"//Service_Information/Data_Information/serv_id"));
					}
					
					//用户查询接口CCR-CCA -> xml
					//SOAP消息返回结果非0，生成网厅错误应答
					if (!result.equals("0")) {
						String errorMsg = "";
						if(!StringUtils.isEmpty(XmlUtils.getNodevalue(root,"//Service_Information/Para_Field_Result"))){
							errorMsg = XmlUtils.getNodevalue(root,"//Service_Information/Para_Field_Result");
						}
						if (logger.isInfoEnabled()) 
						{
							logger.info(" CCR-CCA -> xml " );
						}
						respXML.append(makeErrFormCCA(result,errorMsg));
					}
					else{
						
						//用户查询接口CCR-CCA -> xml
						//SOAP消息返回结果0，生成云平台查询SOAP请求消息
						String sendMsg = makeBlackCardMessage();
						//云平台响应消息
						String responseMsg = null;
						logger.info(" PostMethod url:"+url);
						logger.info(" sendMsg :"+sendMsg );

						//通过httpclient以POST方式向云端发送黑卡查询请求消息。
						RequestEntity requestEntity = new StringRequestEntity(sendMsg, "text/xml", "UTF-8");
						method.setRequestEntity(requestEntity);
						
						int statusCode = httpClient.executeMethod(method);
						if (statusCode != HttpStatus.SC_OK) {
							//httpClient 发送http消息,转态非200，生成网厅错误应答
//							if (logger.isInfoEnabled()) {
								StringBuilder sbInfo = new StringBuilder();
								sbInfo.append("sessionid:").append(blackCardMsgIn.getMid()).append(",");
								sbInfo.append("statusCode:").append(statusCode).append(",");
								sbInfo.append("sendRequest failed:").append(method.getStatusLine());
								logger.info(sbInfo.toString());
								sbInfo.delete( 0, sbInfo.length());
//							}
							respXML.append(makeErrFormCloud(String.valueOf(statusCode),method.getResponseBodyAsString()));
						}
						else {
							responseMsg = IOUtils.toString(method.getResponseBodyAsStream());
//							if (logger.isInfoEnabled()) {
								logger.info(" response message from cloud platform:"+responseMsg);
//							}
							
							//将云平台的相应结果，格式化为网厅所需的xml响应消息
							if (responseMsg != null) {
								doc = DocumentHelper.parseText(responseMsg);
								root = doc.getRootElement();
								org.dom4j.Node returnNode =root.selectSingleNode("//return");
								doc = DocumentHelper.parseText(returnNode.getStringValue());
								root = doc.getRootElement();
								
								String success = XmlUtils.getNodeAttrVal(root,"//HqCheck","success");
								if (!"true".equals(success)) {
									//格式化为异常消息
									String errorCode = XmlUtils.getNodeVal(root,"//HqCheck/errorCode");
									String errorMsg = XmlUtils.getNodeVal(root,"//HqCheck/errorMsg");
									respXML.append(makeErrFormCloud(errorCode,errorMsg));
								}else {
									//格式化为正常消息
									respXML.append(makeSuccMsg(root));
								}
							}
						}
					}
				} catch (DocumentException e) {
					e.printStackTrace();
				}
				catch (Exception e) {
					e.printStackTrace();
				}
				finally {
					if (method != null) {
						method.releaseConnection();
					}
				}
			}
		}
		return respXML.toString();
	}

	/**
	 * 生成成功消息
	 * @param root
	 * @return
	 */
	private String makeSuccMsg(Element root) {
		BlackCardMsgOUt succ = new BlackCardMsgOUt();
		succ.setAccNbr(blackCardMsgIn.getAccNbr());
		succ.setResult("0");
		succ.setServId(blackCardMsgIn.getServId());
		List<DataInfomation>dataInfomations = new ArrayList<DataInfomation>();
		@SuppressWarnings("unchecked")
		List<Element> elements = root.selectNodes("//HqCheck/CkCount/CkMDN");
		if (null!=elements) {
			String ckmdn = "";
			String ckcount = "";
			for(Element element:elements){
				if (null!=element ) {
					if (null!=element.attribute("id")
						&& null!=element.attribute("id").getStringValue()) {
						ckmdn = element.attribute("id").getStringValue();
					}
					if (null!=element.getStringValue()) {
						ckcount = element.getStringValue();
					}
				}
				dataInfomations.add(new DataInfomation(ckmdn, ckcount));
			}
		}
		succ.setDataInfomations(dataInfomations);
		
		StringBuilder sb = new StringBuilder();
		sb.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">");
		sb.append("<SOAP-ENV:Header/>");
		sb.append("<SOAP-ENV:Body>");
		sb.append("<ns3:SgwQueryAck xmlns:ns3=\"http://www.chinatelecom.cn/SGW/SOAP\">");
		sb.append("<MID>");
		sb.append(blackCardMsgIn.getMid());
		sb.append("</MID>");
		sb.append("<REPTAG>0</REPTAG>");		
		sb.append("<RTT>").append(xmlMessage.getRTT()).append("</RTT>");
		sb.append("<SIG>null</SIG>");
		sb.append("<RC>0</RC>");
		sb.append("<DS>SUCCESS</DS>");
		sb.append("<DATA><![CDATA[");
        sb.append(succ.toXml()); 
        sb.append("]]>");
	    sb.append("</DATA>");
	    sb.append("</ns3:SgwQueryAck>");		
	    sb.append("</SOAP-ENV:Body>");
	    sb.append("</SOAP-ENV:Envelope>");	
		return sb.toString();
	}
	
	private String makeErrFormCloud(String result,String msg) {
		BlackCardMsgOUt err = new BlackCardMsgOUt();
		err.setAccNbr(blackCardMsgIn.getAccNbr());
		err.setResult(result);
		err.setRetMsg(msg);
		err.setServId(blackCardMsgIn.getServId());
		err.setEndTime(blackCardMsgIn.getEndTime());
		err.setStartTime(blackCardMsgIn.getStartTime());
		
		StringBuilder sb = new StringBuilder();
		sb.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">");
		sb.append("<SOAP-ENV:Header/>");
		sb.append("<SOAP-ENV:Body>");
		sb.append("<ns3:SgwQueryAck xmlns:ns3=\"http://www.chinatelecom.cn/SGW/SOAP\">");
		sb.append("<MID>");
		sb.append(blackCardMsgIn.getMid());
		sb.append("</MID>");
		sb.append("<REPTAG>0</REPTAG>");		
		sb.append("<RTT>").append(xmlMessage.getRTT()).append("</RTT>");
		sb.append("<SIG>null</SIG>");
		sb.append("<RC>0</RC>");
		sb.append("<DS>SUCCESS</DS>");
		sb.append("<DATA><![CDATA[");
        sb.append(err.toXml()); 
        sb.append("]]>");
	    sb.append("</DATA>");
	    sb.append("</ns3:SgwQueryAck>");		
	    sb.append("</SOAP-ENV:Body>");	
	    sb.append("</SOAP-ENV:Envelope>");	
		
		return sb.toString();
	}

	/**
	 * CCA 消息异常 返回码(RC)为0,Result为非0,业务出错
	 * @param result 业务返回码： Service_Information/Result
	 * @param errorMsgString  错误提示：Service_Information/Para_Field_Result   
	 * @return
	 */
	private String makeErrFormCCA(String result, String errorMsgString ) {
		BlackCardMsgOUt err = new BlackCardMsgOUt();
		err.setAccNbr(blackCardMsgIn.getAccNbr());
		err.setResult(result);
		err.setRetMsg(errorMsgString);
		err.setServId(blackCardMsgIn.getServId());
		err.setEndTime(blackCardMsgIn.getEndTime());
		err.setStartTime(blackCardMsgIn.getStartTime());
		
		StringBuilder sb = new StringBuilder();
		sb.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">");
		sb.append("<SOAP-ENV:Header/>");
		sb.append("<SOAP-ENV:Body>");
		sb.append("<ns3:SgwQueryAck xmlns:ns3=\"http://www.chinatelecom.cn/SGW/SOAP\">");
		sb.append("<MID>");
		sb.append(blackCardMsgIn.getMid());
		sb.append("</MID>");
		sb.append("<REPTAG>0</REPTAG>");		
		sb.append("<RTT>").append(xmlMessage.getRTT()).append("</RTT>");
		sb.append("<SIG>null</SIG>");
		sb.append("<RC>").append(xmlMessage.getRC()).append("</RC>");
		sb.append("<DS>").append(xmlMessage.getDS()).append("</DS>");
		sb.append("<DATA><![CDATA[");
        sb.append(err.toXml()); 
		sb.append("]]>");
	    sb.append("</DATA>");
	    sb.append("</ns3:SgwQueryAck>");		
	    sb.append("</SOAP-ENV:Body>");	
	    sb.append("</SOAP-ENV:Envelope>");	
	    return sb.toString();
	}
	
	/**
	 * CCA 消息异常 返回码(RC)为非0,
	 * @return
	 */
	private String makeErrFormCCA() {
		StringBuilder sb = new StringBuilder();
		sb.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">");
		sb.append("<SOAP-ENV:Header/>");
		sb.append("<SOAP-ENV:Body>");
		sb.append("<ns3:SgwQueryAck xmlns:ns3=\"http://www.chinatelecom.cn/SGW/SOAP\">");
		sb.append("<MID>");
		sb.append(blackCardMsgIn.getMid());
		sb.append("</MID>");
		sb.append("<REPTAG>0</REPTAG>");		
		sb.append("<RTT>").append(xmlMessage.getRTT()).append("</RTT>");
		sb.append("<SIG>null</SIG>");
		sb.append("<RC>").append(xmlMessage.getRC()).append("</RC>");
		sb.append("<DS>").append(xmlMessage.getDS()).append("</DS>");
		sb.append("<DATA><![CDATA[");
		sb.append("]]>");
	    sb.append("</DATA>");
	    sb.append("</ns3:SgwQueryAck>");		
	    sb.append("</SOAP-ENV:Body>");	
	    sb.append("</SOAP-ENV:Envelope>");	
	    return sb.toString();
	}
	

	/**
	 * 拼装黑卡查询接口的发送消息
	 * @return
	 */
	private String makeBlackCardMessage() {
		List<BillInfomation> billInfomations;
		StringBuilder sendMSG = new StringBuilder();
		sendMSG.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ws=\"http://ws.hquery.ailk.com/\">");
		sendMSG.append("<soapenv:Header/>");
		sendMSG.append("<soapenv:Body>");
		sendMSG.append("<ws:hquery>");
		sendMSG.append("<param><![CDATA[ ");
		sendMSG.append("<HqCheck>");
		sendMSG.append(makeNodeStr("BillingMode",blackCardMsgIn.getBillingMode()));
		sendMSG.append(makeNodeStr("MDN",blackCardMsgIn.getAccNbr()));
		sendMSG.append(makeNodeStr("ServId",blackCardMsgIn.getServId()));
		sendMSG.append(makeNodeStr("AreaCode",blackCardMsgIn.getAreaCode()));
		sendMSG.append("<CkMDNlist>");
		billInfomations = blackCardMsgIn.getBillInformations();
		if (null!=billInfomations) {
			for(BillInfomation billInfomation:billInfomations){
				sendMSG.append(makeNodeStr("CkMDN",billInfomation.getCkmdn()));
			}
		}
		sendMSG.append("</CkMDNlist>");
		sendMSG.append(makeNodeStr("StartTime",blackCardMsgIn.getStartTime()));
		sendMSG.append(makeNodeStr("EndTime",blackCardMsgIn.getEndTime()));
		sendMSG.append("</HqCheck>");
		
		sendMSG.append("]]>");
		sendMSG.append("</param>");
		sendMSG.append("</ws:hquery>");
		sendMSG.append("</soapenv:Body>");
		sendMSG.append("</soapenv:Envelope>");
		return sendMSG.toString();
	}

	public String makeNodeStr(String nodeName,String nodeValue) {
		StringBuilder val = new StringBuilder();
		val.append("<");
		val.append(nodeName);
		val.append(">");
		val.append(nodeValue);
		val.append("</");
		val.append(nodeName);
		val.append(">");
		return val.toString();
	}
	@Override
	public int getProtocolType() {
		return 5;
	}

	public HttpClient getHttpClient() {
		return httpClient;
	}

	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public XmlMessage getXmlMessage() {
		return xmlMessage;
	}

	public void setXmlMessage(XmlMessage xmlMessage) {
		this.xmlMessage = xmlMessage;
	}

	public BlackCardConfigService getBlackCardConfigService() {
		return blackCardConfigService;
	}

	public void setBlackCardConfigService(BlackCardConfigService blackCardConfigService) {
		this.blackCardConfigService = blackCardConfigService;
	}

}
